{{#if is_sea_orm_or_sqlx}}
{{#if is_sqlx}}
use crate::{
    app_writer::AppResult,
    db::DB,
    dtos::user::{
        UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse,
        UserUpdateRequest,
    },
    middleware::jwt::get_token,
    entities::users::User,
    utils::rand_utils,
};
{{/if}}
{{#if is_sea_orm}}
use crate::{
    app_writer::AppResult,
    db::DB,
    dtos::user::{
        UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse,
        UserUpdateRequest,
    },
    middleware::jwt::get_token,
    entities::{prelude::Users,users},
    utils::rand_utils,
};
use sea_orm::{EntityTrait, Set, ActiveModelTrait, QueryFilter, ColumnTrait};
{{/if}}
use uuid::Uuid;
{{#if is_sqlx}}
pub async fn add_user(req: UserAddRequest) -> AppResult<UserResponse> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let id = Uuid::new_v4().to_string();
    let hash_password = rand_utils::hash_password(req.password).await?;
    let _ = sqlx::query!(
        r#"
            INSERT INTO users (id, username, password)
            VALUES ($1, $2, $3)
            "#,
        id,
        req.username,
        hash_password,
    )
    .execute(db)
    .await?;

    Ok(UserResponse {
        id,
        username: req.username,
    })
}

pub async fn login(req: UserLoginRequest) -> AppResult<UserLoginResponse> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let user = sqlx::query_as!(
        User,
        r#"
            SELECT id, username, password FROM users
            WHERE username = $1
            "#,
        req.username
    )
    .fetch_optional(db)
    .await?;
    if user.is_none() {
        return Err(anyhow::anyhow!("{{user_does_not_exist}}").into());
    }
    let user = user.unwrap();
    if rand_utils::verify_password(req.password, user.password)
        .await
        .is_err()
    {
        return Err(anyhow::anyhow!("{{incorrect_password}}").into());
    }
    let (token, exp) = get_token(user.username.clone(), user.id.clone())?;
    let res = UserLoginResponse {
        id: user.id,
        username: user.username,
        token,
        exp,
    };
    Ok(res)
}

pub async fn update_user(req: UserUpdateRequest) -> AppResult<UserResponse> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let hash_password = rand_utils::hash_password(req.password).await?;
    let _ = sqlx::query!(
        r#"
            UPDATE users
            SET username = $1, password = $2
            WHERE id = $3
            "#,
        req.username,
        hash_password,
        req.id,
    )
    .execute(db)
    .await?;

    Ok(UserResponse {
        id: req.id,
        username: req.username,
    })
}

pub async fn delete_user(id: String) -> AppResult<()> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    sqlx::query!(
        r#"
            DELETE FROM users
            WHERE id = $1
            "#,
        id,
    )
    .execute(db)
    .await?;

    Ok(())
}

pub async fn users() -> AppResult<Vec<UserResponse>> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let users = sqlx::query_as!(
        User,
        r#"
            SELECT id, username, password FROM users
            "#,
    )
    .fetch_all(db)
    .await?;
    let res = users
        .into_iter()
        .map(|user| UserResponse {
            id: user.id,
            username: user.username,
        })
        .collect::<Vec<_>>();
    Ok(res)
}
{{/if}}
{{#if is_sea_orm}}
pub async fn add_user(req: UserAddRequest) -> AppResult<UserResponse> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let model =users::ActiveModel {
        id: Set(Uuid::new_v4().to_string()),
        username: Set(req.username.clone()),
        password: Set(rand_utils::hash_password(req.password).await?),
    };
    let user = Users::insert(model).exec(db).await?;
    Ok(UserResponse {
        id: user.last_insert_id,
        username: req.username,
    })
}

pub async fn login(req: UserLoginRequest) -> AppResult<UserLoginResponse> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let user = Users::find().filter(users::Column::Username.eq(req.username)).one(db).await?;
    if user.is_none() {
        return Err(anyhow::anyhow!("{{user_does_not_exist}}").into());
    }
    let user = user.unwrap();
    if rand_utils::verify_password(req.password, user.password)
        .await
        .is_err()
    {
        return Err(anyhow::anyhow!("{{incorrect_password}}").into());
    }
    let (token, exp) = get_token(user.username.clone(), user.id.clone())?;
    let res = UserLoginResponse {
        id: user.id,
        username: user.username,
        token,
        exp,
    };
    Ok(res)
}

pub async fn update_user(req: UserUpdateRequest) -> AppResult<UserResponse> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;

    let user = Users::find_by_id(req.id).one(db).await?;
    if user.is_none() {
        return Err(anyhow::anyhow!("{{user_does_not_exist}}").into());
    }
    let mut user: users::ActiveModel = user.unwrap().into();

    user.username = Set(req.username.to_owned());
    user.password = Set(rand_utils::hash_password(req.password).await?);

    let user: users::Model = user.update(db).await?;

    Ok(UserResponse {
        id: user.id,
        username: user.username,
    })
}

pub async fn delete_user(id: String) -> AppResult<()> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    Users::delete_by_id(id).exec(db).await?;
    Ok(())
}

pub async fn users() -> AppResult<Vec<UserResponse>> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let users = Users::find().all(db).await?;
    let res = users
        .into_iter()
        .map(|user| UserResponse {
            id: user.id,
            username: user.username,
        })
        .collect::<Vec<_>>();
    Ok(res)
}
{{/if}}
{{/if}}
{{#if is_diesel}}
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl, SelectableHelper};
use uuid::Uuid;

use crate::schema::users::dsl::users as diesel_users;
use crate::{
    app_writer::AppResult,
    db::establish_connection,
    dtos::user::{
        UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest,
    },
    middleware::jwt::get_token,
    models::user::UserModel,
    utils::rand_utils,
};
use diesel::OptionalExtension;

pub async fn add_user(req: UserAddRequest) -> AppResult<UserResponse> {
    use crate::schema::users;
    let mut db = establish_connection();
    let model = UserModel {
        id: Uuid::new_v4().to_string(),
        username: req.username.clone(),
        password: rand_utils::hash_password(req.password).await?,
    };

    diesel::insert_into(users::table)
        .values(&model)
        .execute(&mut db)
        .expect("Error saving new user");

    let user: UserModel = users::table
        .filter(users::id.eq(&model.id))
        .first(&mut db)
        .expect("Error loading user");

    Ok(UserResponse {
        id: user.id,
        username: user.username,
    })
}

pub async fn login(req: UserLoginRequest) -> AppResult<UserLoginResponse> {
    use crate::schema::users::dsl::*;
    let mut connection = establish_connection();

    let result = diesel_users
        .filter(username.eq(&req.username))
        .select((id, username, password))
        .first::<(String, String, String)>(&mut connection)
        .optional()?;

    match result {
        None => Err(anyhow::anyhow!("{{user_does_not_exist}}").into()),
        Some((uid, uname, hashed_pwd)) => {
            if rand_utils::verify_password(req.password, hashed_pwd)
                .await
                .is_err()
            {
                return Err(anyhow::anyhow!("{{incorrect_password}}").into());
            }

            let (token, exp) = get_token(uname.clone(), uid.clone())?;
            let res = UserLoginResponse {
                id: uid,
                username: uname,
                token,
                exp,
            };
            Ok(res)
        }
    }
}

pub async fn update_user(req: UserUpdateRequest) -> AppResult<UserResponse> {
    use crate::schema::users::dsl::*;
    {{#if is_mysql}}
    let mut db = establish_connection();
    diesel::update(users.find(req.id.clone()))
        .set((
            username.eq(req.username),
            password.eq(rand_utils::hash_password(req.password).await?), 
        ))
        .execute(&mut db)?;

    let user = users
        .find(req.id)
        .select(UserModel::as_select())
        .first(&mut db)?;

    Ok(UserResponse {
        id: user.id,
        username: user.username,
    })
    {{else}}
    let mut db = establish_connection();
    let user = diesel::update(diesel_users.find(req.id))
        .set((
            username.eq(req.username),
            password.eq(rand_utils::hash_password(req.password).await?),
        ))
        .returning(UserModel::as_returning())
        .get_result(&mut db)?;
    Ok(UserResponse {
        id: user.id,
        username: user.username,
    })
    {{/if}}
}

pub async fn delete_user(req: String) -> AppResult<()> {
    use crate::schema::users::id;
    let mut db = establish_connection();
    diesel::delete(diesel_users.filter(id.eq(req)))
        .execute(&mut db)
        .expect("Error deleting posts");
    Ok(())
}

pub async fn users() -> AppResult<Vec<UserResponse>> {
    let mut db = establish_connection();
    let results = diesel_users.select(UserModel::as_select()).load(&mut db)?;

    let res = results
        .into_iter()
        .map(|user| UserResponse {
            id: user.id,
            username: user.username,
        })
        .collect::<Vec<_>>();

    Ok(res)
}
{{/if}}
{{#if is_rbatis}}
use uuid::Uuid;

use crate::{
    app_writer::AppResult,
    dtos::user::{
        UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest,
    },
    middleware::jwt::get_token,
    utils::rand_utils, db::DB, entities::user::Users,
};

pub async fn add_user(req: UserAddRequest) -> AppResult<UserResponse> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let user = Users {
        id: Uuid::new_v4().to_string(),
        username: req.username.clone(),
        password: rand_utils::hash_password(req.password).await?,
    };
    Users::insert(db,&user).await?;

    Ok(UserResponse {
        id: user.id,
        username: user.username,
    })
}

pub async fn login(req: UserLoginRequest) -> AppResult<UserLoginResponse> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let user = Users::select_by_column(db,"username",&req.username).await?;
    if user.len()==0 {
        return Err(anyhow::anyhow!("{{user_does_not_exist}}").into());
    }
    if rand_utils::verify_password(req.password, user[0].password.clone()).await.is_err() {
        return Err(anyhow::anyhow!("{{incorrect_password}}").into());
    }
    let (token, exp) = get_token(user[0].username.clone(), user[0].id.clone())?;
    let res = UserLoginResponse {
        id: user[0].id.clone(),
        username: user[0].username.clone(),
        token,
        exp,
    };
    Ok(res)
}

pub async fn update_user(req: UserUpdateRequest) -> AppResult<UserResponse> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let users = Users::select_by_column(db,"id",&req.id).await?;
    if users.len()==0 {
        return Err(anyhow::anyhow!("{{user_does_not_exist}}").into());
    }
    let user = Users {
        id: users[0].clone().id,
        username: users[0].clone().username,
        password: rand_utils::hash_password(req.password).await?,
    };
    Users::update_by_column(db,&user,"id").await?;
    Ok(UserResponse {
        id: users[0].id.clone(),
        username: users[0].username.clone(),
    })
}

pub async fn delete_user(req: String) -> AppResult<()> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    Users::delete_by_column(db, "id",&req).await?;
    Ok(())
}

pub async fn users() -> AppResult<Vec<UserResponse>> {
    let db = DB.get().ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let users=Users::select_all(db).await?;

    let res = users
        .into_iter()
        .map(|user| UserResponse {
            id: user.id,
            username: user.username,
        })
        .collect::<Vec<_>>();
    Ok(res)
}
{{/if}}
{{#if is_mongodb}}
use crate::{
    app_writer::AppResult,
    db::{COLL_NAME, DB_NAME, MONGODB_CLIENT},
    dtos::user::{
        UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest,
    },
    middleware::jwt::get_token,
    utils::rand_utils,
};
use futures_util::StreamExt;
use mongodb::{
    bson::{doc, oid::ObjectId, Document},
    Collection,
};
use std::str::FromStr;
use validator::Validate;

pub async fn add_user(req: UserAddRequest) -> AppResult<UserResponse> {
    req.validate()?;
    let db = MONGODB_CLIENT
        .get()
        .ok_or(anyhow::anyhow!("数据库连接失败"))?;
    let coll_users = db.database(DB_NAME).collection::<Document>(COLL_NAME);

    let user = doc! {
        "username": req.username,
        "password": rand_utils::hash_password(req.password).await?
    };
    coll_users.insert_one(user.clone(), None).await?;
    let user = coll_users
        .find_one(user, None)
        .await?
        .ok_or(anyhow::anyhow!("用户不存在"))?;
    Ok(UserResponse {
        id: user.get_object_id("_id")?.to_string(),
        username: user.get_str("username")?.to_string(),
    })
}

pub async fn login(req: UserLoginRequest) -> AppResult<UserLoginResponse> {
    let db = MONGODB_CLIENT
        .get()
        .ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let coll_users: Collection<Document> = db.database(DB_NAME).collection(COLL_NAME);

    let user_doc = coll_users
        .find_one(doc! { "username": req.username }, None)
        .await?;

    let user = match user_doc {
        Some(user) => user,
        None => return Err(anyhow::anyhow!("{{user_does_not_exist}}").into()),
    };

    if rand_utils::verify_password(req.password, user.get_str("password")?.to_string())
        .await
        .is_err()
    {
        return Err(anyhow::anyhow!("{{incorrect_password}}").into());
    }
    let (token, exp) = get_token(
        user.get_str("username")?.to_string(),
        user.get_object_id("_id")?.to_string(),
    )?;

    Ok(UserLoginResponse {
        id: user.get_object_id("_id")?.to_string(),
        username: user.get_str("username")?.to_owned(),
        token,
        exp,
    })
}

pub async fn update_user(req: UserUpdateRequest) -> AppResult<UserResponse> {
    let db = MONGODB_CLIENT
        .get()
        .ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let coll_users: Collection<Document> = db.database(DB_NAME).collection(COLL_NAME);
    let id = ObjectId::from_str(&req.id.clone())?;
    let hash_password = rand_utils::hash_password(req.password).await?;
    coll_users
        .update_one(
            doc! { "_id": id },
            doc! { "$set": { "username": req.username.clone(),"password": hash_password } },
            None,
        )
        .await?;
    Ok(UserResponse {
        id: req.id.clone(),
        username: req.username,
    })
}

pub async fn delete_user(req: String) -> AppResult<()> {
    let db = MONGODB_CLIENT
        .get()
        .ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let coll_users: Collection<Document> = db.database(DB_NAME).collection(COLL_NAME);
    let id = ObjectId::from_str(&req)?;

    coll_users.delete_one(doc! { "_id": id }, None).await?;
    Ok(())
}

pub async fn users() -> AppResult<Vec<UserResponse>> {
    let db = MONGODB_CLIENT
        .get()
        .ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?;
    let coll_users: Collection<Document> = db.database(DB_NAME).collection(COLL_NAME);

    let mut cursor = coll_users.find(None, None).await?;
    let mut users = Vec::new();
    while let Some(result) = cursor.next().await {
        let document = result?;
        let id = document.get_object_id("_id")?.to_string();
        let username = document.get_str("username")?.to_owned();
        users.push(UserResponse { id, username });
    }
    Ok(users)
}
{{/if}}
